﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CalculatorLibrary.Computation
{
    public class ComputationTree
    {
        #region Fields
        public ComputationNode valueNode;
        public ComputationTree left;
        public ComputationTree right;
        #endregion //Fields

        #region Constructors
        public ComputationTree()
        {
            valueNode = null;
            left = null;
            right = null;
        }

        public ComputationTree(char type, decimal value)
        {
            Console.WriteLine(type);
            valueNode = new ComputationNode(type, value);
            left = null;
            right = null;
        }
        #endregion //Constructors

        #region Insert
        // Setup a Tree in the format depending on the operator(Return 1 if the expression is invalid.)
        public int Insert(ref ComputationTree curr, String expression)
        {
            char[] operators = { '+', '-', '*', '/', '√', '^', '%', '!', 'g', 's', 'd', 't', 'm', 'n', 'l', 
                               'o', 'h', 'f', 'i', 'a', 'r'};
            int insertPos, i, left = 0, right = 0;
            int pos1 = FindMidChar(expression, '+');
            int pos2 = FindMidChar(expression, '-');

            for(i = 0; i < operators.Length-1; i++)
            {
                pos1 = FindMidChar(expression, operators[i]);
                pos2 = FindMidChar(expression, operators[i+1]);

                // Break out of the loop if we find an operator.
                if (pos1 != -1 || pos2 != -1)
                    break;
            }
            
             
            Console.WriteLine(expression);


                // Error handling checking for if it is a number or not.
                if (pos1 == -1 && pos2 == -1)
                {
                    decimal num;

                    // If Pi is left we need to set it to a value.
                    if (expression == "π")
                        expression = ((decimal)(Math.PI)).ToString();
                    else if (expression == "e")
                        expression = ((decimal)(Math.E)).ToString();

                    //Check if a parantheses exists
                    if (expression.Length != 0 && expression[0] == 'p')
                    {
                        String number = expression[1].ToString();
                        curr = new ComputationTree('p', int.Parse(number));
                        return 0;
                    }

                    bool isNum = decimal.TryParse(expression, out num);

                    if (isNum)
                    {
                        Console.WriteLine("{0}", num);
                        curr = new ComputationTree('c', decimal.Parse(expression));
                        return 0;
                    }

                    //If it is invalid we need to make sure to return 1
                    else
                    {
                        Console.WriteLine("We have reached an invalid statement which is: " + expression);
                        return 1;
                    }
                }

            if (pos1 > pos2)
                insertPos = pos1;
            else
                insertPos = pos2;

            curr = new ComputationTree(expression[insertPos], 0);

            if (!RightOnlyOperatorCheck(expression[insertPos]))
                left = Insert(ref curr.left, expression.Substring(0, insertPos));
            if(!LeftOnlyOperatorCheck(expression[insertPos]))
                right = Insert(ref curr.right, expression.Substring(insertPos+1, (expression.Length-1)-insertPos));
            
            //Check if we have an invalid tree or not
            if (left == 1 || right == 1)
                return 1;

            return 0;
        }
        #endregion //Insert

        #region FindMidChar
        //Used to Find the middle character in the string that is sent in(primarily for efficient insertion into our tree)
        public int FindMidChar(String expression, char oper)
        {
            List<int> positions = new List<int>();

            if (expression == null || expression.Length == 0)
                return -1;

            //Exit case if character does not exist
            if (!expression.Contains(oper))
            {
                return -1;
            }

            for (int i = 0; i < expression.Length; i++)
            {
                if (expression[i] == oper)
                    positions.Add(i);
            }

            int middle = positions.Count / 2;

            return positions[middle];
        }
        #endregion //FindMidChar

        #region LeftOnlyOperatorCheck
        // Verify is we have a left only operator.
        public bool LeftOnlyOperatorCheck(char check)
        {
            switch (check)
            {
                case '%':
                    return true;
                case '!':
                    return true;
            }

            return false;
        }
        #endregion //LeftOnlyOperatorCheck

        #region RightOnlyOperatorCheck
        //Verify if we have a right only operator
        public bool RightOnlyOperatorCheck(char check)
        {
            switch (check)
            {
                case 's':
                    return true;

                case 'd':
                    return true;

                case 't':
                    return true;

                case 'n':
                    return true;

                case 'l':
                    return true;

                case 'o':
                    return true;

                case 'h':
                    return true;

                case 'f':
                    return true;

                case 'i':
                    return true;

                case 'a':
                    return true;

                case 'r':
                    return true;

                case 'g':
                    return true;

            }
            return false;
        }
        #endregion //RightOnlyOperator
    }
}
